/*
 *    Copyright 2009-2014 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.resultset;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.loader.ResultLoader;
import org.apache.ibatis.executor.loader.ResultLoaderMap;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.result.DefaultResultContext;
import org.apache.ibatis.executor.result.DefaultResultHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.reflection.MetaClass;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.*;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.lang.reflect.Constructor;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;

/**
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
/**
 * 默认Map结果处理器
 *
 */
public class DefaultResultSetHandler implements ResultSetHandler {

  private static final Object NO_VALUE = new Object();

  private final Executor executor;
  private final Configuration configuration;
  private final MappedStatement mappedStatement;
  private final RowBounds rowBounds;
  private final ParameterHandler parameterHandler;
  /**
   * 用户指定用于处理结果集 ResultHandler 对象
   */
  private final ResultHandler resultHandler;
  private final BoundSql boundSql;

  private final TypeHandlerRegistry typeHandlerRegistry;
  /**
   * 对象工厂
   */
  private final ObjectFactory objectFactory;

  // nested resultmaps
  private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();
  private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>();
  private final Map<String, String> ancestorColumnPrefix = new HashMap<String, String>();

  // multiple resultsets
  private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();
  private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();

  private static class PendingRelation {
    public MetaObject metaObject;
    public ResultMapping propertyMapping;
  }

  public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql,
      RowBounds rowBounds) {
    this.executor = executor;
    this.configuration = mappedStatement.getConfiguration();
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;
    this.parameterHandler = parameterHandler;
    this.boundSql = boundSql;
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();
    this.resultHandler = resultHandler;
  }

  //
  // HANDLE OUTPUT PARAMETER
  //

  @Override
  public void handleOutputParameters(CallableStatement cs) throws SQLException {
    //获取用户传入的实际参数，并为其创建相应的 MetaObject 对象
    final Object parameterObject = parameterHandler.getParameterObject();
    final MetaObject metaParam = configuration.newMetaObject(parameterObject);
    //获取 BoundSql parameterMappings 集合， 其中记录了参数相关信息，请读者回顾前面的相关介
    final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    //循环处理每个参数
    for (int i = 0; i < parameterMappings.size(); i++) {
      final ParameterMapping parameterMapping = parameterMappings.get(i);
      //只处理OUT|INOUT
      if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
        if (ResultSet.class.equals(parameterMapping.getJavaType())) {
          //如果是ResultSet型(游标)
          //#{result, jdbcType=CURSOR, mode=OUT, javaType=ResultSet, resultMap=userResultMap}
          //先用CallableStatement.getObject取得这个游标，作为参数传进去
          handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
        } else {
          //否则是普通型，核心就是CallableStatement.getXXX取得值
          final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
          metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
        }
      }
    }
  }

  //处理游标(OUT参数)
  private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {
    try {
      //获取映射使用的 ResultMap 对象
      final String resultMapId = parameterMapping.getResultMapId();
      final ResultMap resultMap = configuration.getResultMap(resultMapId);
      // 创建用 保存映结果集对象 DefaultResultHandler 对象
      final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
      //将结果集封装成 ResultSetWrapper
      final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
      //里面就和一般ResultSet处理没两样了
      //通过 handleRowValues()方法完成映射操作，并将结果对象保存到 DefaultResultHandler
      handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
      //／将映射得的结果对象保存圭1] parameterObject
      metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
    } finally {
      // issue #228 (close resultsets)
      closeResultSet(rs);
    }
  }

  //
  // HANDLE RESULT SETS
  //
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    //该集合用于保存映射结果集得到的结果对象
    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;
    // 获取第一个 ResultSet 对象，正如前面所说，可能存在多个 ResultSet ，这里只获取第一个 ResultSet
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    //获取 MappedStatement.resultMaps 集合，前面分析 MyBatis 初始化 介绍过 ，映射文件中的
    //<resultMap>节点会被解析成 ResultMap 对象 保存到 MappedStatement.resultMaps 集合中
    //如采 SQL 节点能够产生多个 ResultSet ，那么我们可以在 SQL 节点的 resultMap属性中配置多个
    //<resultMap>节点的 id ，它们之间通过","分隔，实现对多个结采集的映射
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    //一般resultMaps里只有一个元素
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    //遍历resultMaps 集合
    while (rsw != null && resultMapCount > resultSetCount) {
      //获取该结果集对应的 ResultMap 对象
      ResultMap resultMap = resultMaps.get(resultSetCount);
      //根据 ResultMap 义的映射规则对 ResultSet 进行映射 并将映射的结采对象添加到
      // multipleResults 集合中保存
      handleResultSet(rsw, resultMap, multipleResults, null);
      //／获取下一个结采集
      rsw = getNextResultSet(stmt);
      //清空 nestedResultObjects 集合
      cleanUpAfterHandlingResultSet();
      //递增 resultSetCount
      resultSetCount++;
    }
    //获 Mapp != dStatement.resultSets属性,该属性仅对多结果集的情况适用，该属性将列出语句执
    //行后返回的结果集，并给每个结果集一个名称，名称是逗号分隔的
    //这里会根据 ResultSet 的名称处理嵌套映射，在本节后续部分还会结合示例详述该过程，读者可以暂
    //时不必深究下面这部分代码
    String[] resultSets = mappedStatement.getResulSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        //／根据 resultSet 的名称，获取未处理的 ResultMapping
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          //根据 ResultMap 对象映射结果集
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        //获取下一个结果集
        rsw = getNextResultSet(stmt);
        //清空 nestedResultObjects 集合
        cleanUpAfterHandlingResultSet();
        //递增 resultSetCount
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

  private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    // 获取 ResultSet 对象
    ResultSet rs = stmt.getResultSet();
    //HSQLDB2.1特殊情况处理
    while (rs == null) {
      // move forward to get the first resultset in case the driver
      // doesn't return the resultset as the first result (HSQLDB 2.1)
      //检测是否还有待处理的 ResultSet
      if (stmt.getMoreResults()) {
        rs = stmt.getResultSet();
      } else {
        //没有待处理的 ResultSet
        if (stmt.getUpdateCount() == -1) {
          // no more results. Must be no resultset
          break;
        }
      }
    }
    //／将给结果集装成 ResultSetWrapper 对象
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }

  private ResultSetWrapper getNextResultSet(Statement stmt) throws SQLException {
    // Making this method tolerant of bad JDBC drivers
    //检测 JDBC 是否支持多结果集
    try {
      if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
        // Crazy Standard JDBC way of determining if there are more results
        //检测是否还有待处理结果集,若存在， 封装成 ResultSetWrapper 对象并返回
        if (!((!stmt.getMoreResults()) && (stmt.getUpdateCount() == -1))) {
          ResultSet rs = stmt.getResultSet();
          return rs != null ? new ResultSetWrapper(rs, configuration) : null;
        }
      }
    } catch (Exception e) {
      // Intentionally ignored.
    }
    return null;
  }

  private void closeResultSet(ResultSet rs) {
    try {
      if (rs != null) {
        rs.close();
      }
    } catch (SQLException e) {
      // ignore
    }
  }

  private void cleanUpAfterHandlingResultSet() {
    nestedResultObjects.clear();
    ancestorColumnPrefix.clear();
  }

  private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
    if (rsw != null && resultMapCount < 1) {
      throw new ExecutorException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
          + "'.  It's likely that neither a Result Type nor a Result Map was specified.");
    }
  }

  //处理结果集
  private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        if (resultHandler == null) {
          //如果没有resultHandler
          //新建DefaultResultHandler
          //处理多结果集中的嵌套映射，例如前面示例中的名为"authors"的 ResultSet ，就是此处
          //逻辑实现映射的
          //如果用户未指定处理映射结果对象 ResultHandler 对象 则使用 DefaultResultHandler
          //作为默认的 ResultHandler 对象
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          //调用自己的handleRowValues
          //对 ResultSet 进行映射，并将映射得到的结果对象添加到 DefaultResultHandler 对象中暂存
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          //得到记录的list
          //将 DefaultResultHandler 中保存的结果对象添加到 multipleResults 集合中
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          //如果有resultHandler
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      //最后别忘了关闭结果集，这个居然出bug了
      // issue #228 (close resultsets)
      //调用 ResultSet.close()方法关闭结果集
      closeResultSet(rsw.getResultSet());
    }
  }

  @SuppressWarnings("unchecked")
  private List<Object> collapseSingleResultList(List<Object> multipleResults) {
    return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
  }

  //
  // HANDLE ROWS FOR SIMPLE RESULTMAP
  //

  private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    //针对存在嵌套 ResultMap 情况
    if (resultMap.hasNestedResultMaps()) {
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
      //针对不含嵌套映射的简单映射的处理
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }

  private void ensureNoRowBounds() {
    if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {
      throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. "
          + "Use safeRowBoundsEnabled=false setting to bypass this check.");
    }
  }

  protected void checkResultHandler() {
    if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {
      throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "
          + "Use safeResultHandlerEnabled=false setting to bypass this check "
          + "or ensure your statement returns ordered data and set resultOrdered=true on it.");
    }
  }

  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext resultContext = new DefaultResultContext();
    skipRows(rsw.getResultSet(), rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }

  private void storeObject(ResultHandler resultHandler, DefaultResultContext resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
    if (parentMapping != null) {
      //嵌套查询或嵌套映射，将结果对象保存到父对象对应的属性中，后面详细介绍
      linkToParents(rs, parentMapping, rowValue);
    } else {
      //普通映射,将结果对象保存到 ResultHandler中
      callResultHandler(resultHandler, resultContext, rowValue);
    }
  }

  private void callResultHandler(ResultHandler resultHandler, DefaultResultContext resultContext, Object rowValue) {
    //递增 DefaultResultContext.resultCount,该值用于检测处理的记录行数是否已经达到
    //上限（在 RowBounds.limit 字段中记录了该上限） 之后将结果对象保存到
    //DefaultResultContext.resultObject字段中
    resultContext.nextResultObject(rowValue);
    //／将结果对象添加到 ResultHandler.resultList 中保存
    resultHandler.handleResult(resultContext);
  }

  private boolean shouldProcessMoreRows(ResultContext context, RowBounds rowBounds) throws SQLException {
    //一个是检测 DefaultResultContext.stopped 字段，另一个是检测映射行数是否达
    //到了 RowBounds.limit的限制
    return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
  }

  private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
    // 根据 ResultSet 的类型进行定位
    if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
      if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
        //直接定位到 offset 指定的记录
        rs.absolute(rowBounds.getOffset());
      }
    } else {
      //通过多次调用 ResultSet.next()方法移动到指定的记录
      for (int i = 0; i < rowBounds.getOffset(); i++) {
        rs.next();
      }
    }
  }

  //
  // GET VALUE FROM ROW FOR SIMPLE RESULT MAP
  //

  //核心，取得一行的值
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
    //实例化ResultLoaderMap(延迟加载器)
    //ResultLoaderMap 与延迟加载相关
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //调用自己的createResultObject,内部就是new一个对象(如果是简单类型，new完也把值赋进去)
    //步骤1：创建该行记录映射之后得到的结果对象， 该结采对象的类型由＜resultMap＞节点的 type 属性指定
    Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
    if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
      //一般不是简单类型不会有typehandler,这个if会进来
      //创建上述结果对象相应的 MetaObject 对象
      final MetaObject metaObject = configuration.newMetaObject(resultObject);
      //成功映射任意属性，则 foundValues为true 否则 foundValues为false
      boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
      //检测是否需要进行自动映射
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        //自动映射咯
        //这里把每个列的值都赋到相应的字段里去了
        //步骤2:自动映射 ResultMap 中未明确指定的列
    	foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
      }
      //步骤3：映射 ResultMap 中明确指定需要映射的列
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
      //步骤4：如果没有成功映射任何属性，则根据 mybatis-config.xml 中的
      //<returnInstanceForEmptyRow＞配置决定返回空的结果对象还是返回 null
      foundValues = lazyLoader.size() > 0 || foundValues;
      resultObject = foundValues ? resultObject : null;
      return resultObject;
    }
    return resultObject;
  }

  private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
    //获取 ResultMap 中的 autoMapping 属性值
    if (resultMap.getAutoMapping() != null) {
      return resultMap.getAutoMapping();
    } else {
      //／检测是否为嵌套查询或是嵌套映射
      if (isNested) {
        return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
      } else {
        return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
      }
    }
  }

  //
  // PROPERTY MAPPINGS
  //

  private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    // 获取该 ResultMap 中明确需妥进行映射的列名 集合
    final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
    //获取 ResultMap.propertyResultMappings 集合，其中记录了映射使用的所有 ResultMapping 对象
    //该集合的填充过程，读者可以回顾 MyBatis 的初始化过程
    final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
    for (ResultMapping propertyMapping : propertyMappings) {
      //处理列前缀
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      //下面的逻辑主要处理三种场景
      //场景 column "{propl=coll,prop2=co12}”这种形式的，一般与嵌套查询配合使用，
      //表示将 col和ol2 的列位传递给 内层嵌套查询作为参数
      //场景 ：基本类型的属性映射
      //场景 ：多结果集的场景处理，该属性来自另一个结果集
      //if (propertyMapping.isCompositeResult （）／／一
      if (propertyMapping.isCompositeResult()  //场景1
          || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) //场景2
          || propertyMapping.getResultSet() != null) { //场景3
        //通过 getPropertyMappingValue()方法完成映射，并得到属性值
        Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
        // issue #541 make property optional
        //获取属性名称
        final String property = propertyMapping.getProperty();
        // issue #377, call setter on nulls
        if (value != NO_VALUE && property != null && (value != null || configuration.isCallSettersOnNulls())) {
          if (value != null || !metaObject.getSetterType(property).isPrimitive()) {
            // 设置属性值
            metaObject.setValue(property, value);
          }
          //DEFERED 表示的是占位符对象，在后面介绍 ResultLoader DeferredLoad 时，
          //会详细介绍延迟加载的原理和实现
          foundValues = true;
        }
      }
    }
    return foundValues;
  }

  private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    // 嵌套查询，后面详细介绍
    if (propertyMapping.getNestedQueryId() != null) {
      return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
      //多结果集的处理，后面详细介绍
    } else if (propertyMapping.getResultSet() != null) {
      addPendingChildRelation(rs, metaResultObject, propertyMapping);
      //返回占位符对象
      return NO_VALUE;
    } else if (propertyMapping.getNestedResultMapId() != null) {
      // the user added a column attribute to a nested result map, ignore it
      return NO_VALUE;
    } else {
      //获取 ResultMapping 中记录的 TypeHandler 对象
      final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      //使用 TypeHandler 对象获取属性值
      return typeHandler.getResult(rs, column);
    }
  }

  //自动映射咯
  private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
    final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
    for (String columnName : unmappedColumnNames) {
      String propertyName = columnName;
      if (columnPrefix != null && !columnPrefix.isEmpty()) {
        // When columnPrefix is specified,
        // ignore columns without the prefix.
        if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
          propertyName = columnName.substring(columnPrefix.length());
        } else {
          continue;
        }
      }
      final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
      if (property != null && metaObject.hasSetter(property)) {
        final Class<?> propertyType = metaObject.getSetterType(property);
        if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
          final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
          //巧妙的用TypeHandler取得结果
          final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
          // issue #377, call setter on nulls
          if (value != null || configuration.isCallSettersOnNulls()) {
            if (value != null || !propertyType.isPrimitive()) {
              //然后巧妙的用反射来设置到对象
              metaObject.setValue(property, value);
            }
            foundValues = true;
          }
        }
      }
    }
    return foundValues;
  }

  // MULTIPLE RESULT SETS

  private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
    //创建 CacheKey 对象 注意这里构成 CacheKey 的第三部分，它换成 外键的值
    CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
    //获取 pendingRelations 集合中 parentKey 对应的 PendingRelation 对象
    List<PendingRelation> parents = pendingRelations.get(parentKey);
    for (PendingRelation parent : parents) {
      if (parent != null) {
        final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(parent.propertyMapping, parent.metaObject);
        if (rowValue != null) {
          if (collectionProperty != null) {
            final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
            targetMetaObject.add(rowValue);
          } else {
            parent.metaObject.setValue(parent.propertyMapping.getProperty(), rowValue);
          }
        }
      }
    }
  }

  private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
    //获取指定的属性名称和当前属性值
    final String propertyName = resultMapping.getProperty();
    Object propertyValue = metaObject.getValue(propertyName);
    //检测该属性是否已初始化
    if (propertyValue == null) {
      //获取属性的 Java 类型
      Class<?> type = resultMapping.getJavaType();
      if (type == null) {
        type = metaObject.getSetterType(propertyName);
      }
      try {
        //指定属性为集合类型
        if (objectFactory.isCollection(type)) {
          //通过 ObjectFactory 创建该类型的集合对象 并进行相应设置
          propertyValue = objectFactory.create(type);
          metaObject.setValue(propertyName, propertyValue);
          return propertyValue;
        }
      } catch (Exception e) {
        throw new ExecutorException("Error instantiating collection property for result '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
      }
    } else if (objectFactory.isCollection(propertyValue.getClass())) {
      //指定属性是集合类型且已经初始化，则返回该属性位
      return propertyValue;
    }
    return null;
  }

  private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {
    //步骤1、为指定结果集创建 CacheKey 对象
    CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());
    //步骤2、创建 PendingRelation 对象
    PendingRelation deferLoad = new PendingRelation();
    deferLoad.metaObject = metaResultObject;
    deferLoad.propertyMapping = parentMapping;
    //步骤3、将 PendingRelation 对象添加到 pendingRelations 缓存
    List<PendingRelation> relations = pendingRelations.get(cacheKey);
    // issue #255
    if (relations == null) {
      relations = new ArrayList<DefaultResultSetHandler.PendingRelation>();
      pendingRelations.put(cacheKey, relations);
    }
    relations.add(deferLoad);
    //步骤4、在 nextResultMaps 集合记录指定属性对应的结果集名称以及对应的 ResultMapping 对象
    ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
    if (previous == null) {
      nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
    } else {
      if (!previous.equals(parentMapping)) {
        throw new ExecutorException("Two different properties are mapped to the same resultSet");
      }
    }
  }

  private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {
    CacheKey cacheKey = new CacheKey();
    //添加 ResultMapping
    cacheKey.update(resultMapping);
    if (columns != null && names != null) {
      //按照逗号切分列名
      String[] columnsArray = columns.split(",");
      String[] namesArray = names.split(",");
      for (int i = 0 ; i < columnsArray.length ; i++) {
        //查询该行记录对应列的位
        Object value = rs.getString(columnsArray[i]);
        if (value != null) {
          //添加列名和列位
          cacheKey.update(namesArray[i]);
          cacheKey.update(value);
        }
      }
    }
    return cacheKey;
  }

  //
  // INSTANTIATION & CONSTRUCTOR MAPPING
  //

  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
    final List<Object> constructorArgs = new ArrayList<Object>();
    //创建该行记录对应的结果对象
    final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // issue gcode #109 && issue #149
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          //TODO 使用代理(cglib/javaassist)
          return configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
        }
      }
    }
    return resultObject;
  }

  //创建结果对象
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
	//得到result type
    //获 ResultMap中记录type属性 ，也就是该行记录最终映射成的结果对象类型
    final Class<?> resultType = resultMap.getType();
    //创建该类型对应的 MetaClass 对象
    final MetaClass metaType = MetaClass.forClass(resultType);
    //获取 ResultMap 中记录的 <constructor> 节点信息，如果该集合不为空，则可以通过该集合确定相应
    //Java 中的唯一构造函数
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    //创建结果对象分为下面 种场景
    //场景1：结果集只有一列，且存在 TypeHandler 对象可以将该列转换成 resultType 类型的值
    if (typeHandlerRegistry.hasTypeHandler(resultType)) {
      //基本型
      //先查找相应的 TypeHandler 对象，再使用 TypeHandler 对象将该记录转换成 Java 类型的值
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
      //场景2
      //有参数的构造函数
      //ResultMap 中记录<constructor>节点的信息，则通过反射方式调用构造方法，创建结果对象
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      //普通bean类型
      //场景3 使用默认的无参构造函数，则直接使用 ObjectFactory 创建对象
      return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      //自动映射
      //场景4：通过自动映射的方式查找合适的构造方法并创建结果对象
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }

  private Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
      List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException {
    boolean foundValues = false;
    //遍历 constructorMappings 集合，该过程中会使用 constructorArgTypes 集合记录构造参数类
    //型，使用 constructorArgs 集合记录构造函数实参
    for (ResultMapping constructorMapping : constructorMappings) {
      //获取当前构造参数的类型
      final Class<?> parameterType = constructorMapping.getJavaType();
      final String column = constructorMapping.getColumn();
      final Object value;
      if (constructorMapping.getNestedQueryId() != null) {
        //存在嵌套查询，需妥处理该查询，然后才白色得到实参， 面有专门的一小节详述嵌套查询的处理逻辑
        value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
      } else if (constructorMapping.getNestedResultMapId() != null) {
        //存在嵌套映射，需妥先处理嵌套映射，才肯 寻到实参，在 有专门一小节详述嵌套映射的处理逻辑
        final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
        value = getRowValue(rsw, resultMap);
      } else {
        //直接获取该列的位，然后经过 TypeHandler 对象的转换，得到构造函数的实参
        final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
        value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
      }
      //记录当前构造参数的类型
      constructorArgTypes.add(parameterType);
      //记录当前构造参数的实际值
      constructorArgs.add(value);
      foundValues = value != null || foundValues;
    }
    //通过 ObjectFactory 调用匹配的构造函数，创建结果对象
    return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
  }

  private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs,
      String columnPrefix) throws SQLException {
    //遍历全部的构造方法
    for (Constructor<?> constructor : resultType.getDeclaredConstructors()) {
      //／查找合适的构造方法，该构造方法的参数类型与 ResultSet 中列所对应的 Java 类型匹配
      if (typeNames(constructor.getParameterTypes()).equals(rsw.getClassNames())) {
        boolean foundValues = false;
        for (int i = 0; i < constructor.getParameterTypes().length; i++) {
          //获取构造函数的参数类型
          Class<?> parameterType = constructor.getParameterTypes()[i];
          //ResultSet 中的列名
          String columnName = rsw.getColumnNames().get(i);
          //查找对应的 TypeHandler ，并获取该列的位
          TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
          Object value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(columnName, columnPrefix));
          //／记录构造函数的参数类型和参数值
          constructorArgTypes.add(parameterType);
          constructorArgs.add(value);
          //更新 foundValues值
          foundValues = value != null || foundValues;
        }
        //上面是构造函数创建对象，下面是对象工厂来创建
        //使用 ObjectFactory 调用对应的构造方法 建结果对象
        return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
      }
    }
    throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
  }

  private List<String> typeNames(Class<?>[] parameterTypes) {
    List<String> names = new ArrayList<String>();
    for (Class<?> type : parameterTypes) {
      names.add(type.getName());
    }
    return names;
  }

  //简单类型走这里
  private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final String columnName;
    if (!resultMap.getResultMappings().isEmpty()) {
      final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
      final ResultMapping mapping = resultMappingList.get(0);
      columnName = prependPrefix(mapping.getColumn(), columnPrefix);
    } else {
      //因为只有1列，所以取得这一列的名字
      columnName = rsw.getColumnNames().get(0);
    }
    final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
    return typeHandler.getResult(rsw.getResultSet(), columnName);
  }

  //
  // NESTED QUERY
  //

  private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
    // 获取嵌套查询的 id 以及对应 MappedStatement 对象
    final String nestedQueryId = constructorMapping.getNestedQueryId();
    final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
    final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
    //获取传递给嵌套查询的参数值
    final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);
    Object value = null;
    if (nestedQueryParameterObject != null) {
      //获取嵌套查询对应的 BoundSql 对象和相应的 CacheKey 对象
      final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
      final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
      //获取嵌套查询结果集经过映射后的目标类型
      final Class<?> targetType = constructorMapping.getJavaType();
      //创建 ResultLoader 对象，并调用 loadResult()方法执行嵌套查询，得到相应的构造方法参数值
      final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
      value = resultLoader.loadResult();
    }
    return value;
  }

  //得到嵌套查询值
  private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
    //获取嵌套查询的 id 和对应的 MappedStatement 对象
    final String nestedQueryId = propertyMapping.getNestedQueryId();
    final String property = propertyMapping.getProperty();
    final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
    //获取传递给嵌套查询的参数类型和参数值
    final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
    final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
    Object value = NO_VALUE;
    if (nestedQueryParameterObject != null) {
      //获取嵌套查 对应 BoundSql 对象和相应 CacheKey 对象
      final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
      final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
      //获取嵌套查询结果集经过映射后的目标类型
      final Class<?> targetType = propertyMapping.getJavaType();
      if (executor.isCached(nestedQuery, key)) {
    	//如果已经有一级缓存了，则延迟加载(实际上deferLoad方法中可以看到则是立即加载)
        executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
      } else {
    	//否则lazyLoader.addLoader 需要延迟加载则addLoader
    	//或者ResultLoader.loadResult 不需要延迟加载则立即加载
        final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
        if (propertyMapping.isLazy()) {
          lazyLoader.addLoader(property, metaResultObject, resultLoader);
        } else {
          value = resultLoader.loadResult();
        }
      }
    }
    return value;
  }

  private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
    if (resultMapping.isCompositeResult()) {
      return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
    } else {
      return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
    }
  }

  private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
    final TypeHandler<?> typeHandler;
    if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
      typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
    } else {
      typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
    }
    return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
  }

  private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
    final Object parameterObject = instantiateParameterObject(parameterType);
    final MetaObject metaObject = configuration.newMetaObject(parameterObject);
    boolean foundValues = false;
    for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
      final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
      final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
      final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
      // issue #353 & #560 do not execute nested query if key is null
      if (propValue != null) {
        metaObject.setValue(innerResultMapping.getProperty(), propValue);
        foundValues = true;
      }
    }
    return foundValues ? parameterObject : null;
  }

  private Object instantiateParameterObject(Class<?> parameterType) {
    if (parameterType == null) {
      return new HashMap<Object, Object>();
    } else {
      return objectFactory.create(parameterType);
    }
  }

  //
  // DISCRIMINATOR
  //

  public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
    //记录已经处理过的 ResultMap的id
    Set<String> pastDiscriminators = new HashSet<String>();
    //获取 ResultMap 中的 Discriminator 对象。前面的构造过程也介绍过<discriminator>节点对应生
    //成的是 Discriminator 对象并记录到 ResultMap.discriminator 字段中，而不是生成 ResultMapping
    //对象
    Discriminator discriminator = resultMap.getDiscriminator();
    while (discriminator != null) {
      //获取记录中对应列的值，其中会使用相应的 TypeHandler 对象将该列转换成 Java 类型
      final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
      //根据该如 值获取对应的 ResultMap的id ，例如，示例 中的 result2
      final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
      if (configuration.hasResultMap(discriminatedMapId)) {
        //／根据上述步骤获取的id ，查找相应的 ResultMap 对象
        resultMap = configuration.getResultMap(discriminatedMapId);
        //／记录当前 Discriminator 对象
        Discriminator lastDiscriminator = discriminator;
        //获取 ResultMap 对象中的 Discriminator
        discriminator = resultMap.getDiscriminator();
        //检测 Discriminator 是否 出现了环形引用
        if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
          break;
        }
      } else {
        break;
      }
    }
    // ResultMap 对象为映射最终使用的 ResultMap
    return resultMap;
  }

  private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
    final ResultMapping resultMapping = discriminator.getResultMapping();
    final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
    return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
  }

  private String prependPrefix(String columnName, String prefix) {
    if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
      return columnName;
    }
    return prefix + columnName;
  }

  //
  // HANDLE NESTED RESULT MAPS
  //

  private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    // 默认上下文对象
    final DefaultResultContext resultContext = new DefaultResultContext();
    //步骤1：根据 RowBounds 中的 offset 定位到指定的记录
    skipRows(rsw.getResultSet(), rowBounds);
    Object rowValue = null;
    //步骤2：检测已经处理的行数是否已经达到上眼（RowBounds.limit）以及 ResultSet 中是否还有可处理的记录
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      // 步骤3：根据该行记录以及 ResultMap.discriminator ，决定映射使用的 ResultMap
      final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
      Object partialObject = nestedResultObjects.get(rowKey);
      // issue #577 && #542
      if (mappedStatement.isResultOrdered()) {
        if (partialObject == null && rowValue != null) {
          nestedResultObjects.clear();
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
        //步骤4：根据最终确定的 ResultMap对ResultSet中的该行记录进行映射，得到映射后的结采对象
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
      } else {
        //步骤4：根据最终确定的 ResultMap对ResultSet中的该行记录进行映射，得到映射后的结采对象
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
        if (partialObject == null) {
          //步骤5：将映射创建的结果对象添加到ResultHandler.resultList 中保存
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
      }
    }
    if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }

  //
  // GET VALUE FROM ROW FOR NESTED RESULT MAP
  //

  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey, String columnPrefix, Object partialObject) throws SQLException {
    final String resultMapId = resultMap.getId();
    Object resultObject = partialObject;
    //／步骤1 检测外层对象是否已经存在
    if (resultObject != null) {
      final MetaObject metaObject = configuration.newMetaObject(resultObject);
      //步骤 3.1 ：将外层对象添加到 ancestorObjects 集合中
      putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
      //步骤 3.2 ：处理嵌套映射
      applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
      //步骤3.3 ：将外层对象从 ancestorObjects 集合中移除
      ancestorObjects.remove(absoluteKey);
    } else {
      //延迟加载
      final ResultLoaderMap lazyLoader = new ResultLoaderMap();
      //步骤2.1 ：创建外层对象
      resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
      if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
        final MetaObject metaObject = configuration.newMetaObject(resultObject);
        boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
        //／更新 foundValues ，其含义与简单映射中同名交量相同：成功映射任意属性，则foundValues为
        //true;否则 foundValues为false
        //步骤 2.2 ：自动映射
        if (shouldApplyAutomaticMappings(resultMap, true)) {
          foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        //步骤2.3 ：映射 ResultMap 中明确指定的字段
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        //步骤 2.4 ：将外层对象添加到 ancestorObjects 集合中
        putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
        //步骤 2.5：处理嵌套映射
        foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
        //／步骤 2.6：将外层对象从 ancestorObjects 集合中移除
        ancestorObjects.remove(absoluteKey);
        foundValues = lazyLoader.size() > 0 || foundValues;
        resultObject = foundValues ? resultObject : null;
      }
      if (combinedKey != CacheKey.NULL_CACHE_KEY) {
        //步骤 2.7 ：将外层对象保存到 nestedResultObjects集合中，待映射后续记录时使用
        nestedResultObjects.put(combinedKey, resultObject);
      }
    }
    return resultObject;
  }

  private void putAncestor(CacheKey rowKey, Object resultObject, String resultMapId, String columnPrefix) {
    if (!ancestorColumnPrefix.containsKey(resultMapId)) {
      ancestorColumnPrefix.put(resultMapId, columnPrefix);
    }
    ancestorObjects.put(rowKey, resultObject);
  }

  //
  // NESTED RESULT MAP (JOIN MAPPING)
  //

  private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
    boolean foundValues = false;
    //追历全部 ResultMapping 对象，处理其中的嵌套映射
    for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
      //获取 ResultMapping.nestedResultMapId
      final String nestedResultMapId = resultMapping.getNestedResultMapId();
      //步骤1: 检测 nestedResultMapId和resultSet 两个字段的值
      if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
        try {
          //获取列前缀
          final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
          //步骤2：确定嵌套映射使用的 ResultMap 对象，具体实现前面已经分析过，不再重复
          final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
          CacheKey rowKey = null;
          Object ancestorObject = null;
          if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
            rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
            ancestorObject = ancestorObjects.get(rowKey);
          }
          if (ancestorObject != null) {
            if (newObject) {
              metaObject.setValue(resultMapping.getProperty(), ancestorObject);
            }
          } else {
            rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
            //步骤4 为嵌套对象创建 CacheKey 对象
            final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
            //／查找 nestedResultObjects 集合中是否有相同的 Key 的嵌套对象
            Object rowValue = nestedResultObjects.get(combinedKey);
            boolean knownValue = (rowValue != null);
            //步骤5：初始化外层对象中 Collection 类型的属性
            final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
            //步骤6：根据 notNullColumn 属性检测结果集中的空位
            if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
              //步骤7：完成嵌套映射，并生成嵌套对象
              rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
              if (rowValue != null && !knownValue) {
                if (collectionProperty != null) {
                  final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
                  targetMetaObject.add(rowValue);
                } else {
                  metaObject.setValue(resultMapping.getProperty(), rowValue);
                }
                foundValues = true;
              }
            }
          }
        } catch (SQLException e) {
          throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
        }
      }
    }
    return foundValues;
  }

  private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
    final StringBuilder columnPrefixBuilder = new StringBuilder();
    if (parentPrefix != null) {
      columnPrefixBuilder.append(parentPrefix);
    }
    if (resultMapping.getColumnPrefix() != null) {
      columnPrefixBuilder.append(resultMapping.getColumnPrefix());
    }
    return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
  }

  private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSet rs) throws SQLException {
    Set<String> notNullColumns = resultMapping.getNotNullColumns();
    boolean anyNotNullColumnHasValue = true;
    if (notNullColumns != null && !notNullColumns.isEmpty()) {
      anyNotNullColumnHasValue = false;
      for (String column: notNullColumns) {
        rs.getObject(prependPrefix(column, columnPrefix));
        if (!rs.wasNull()) {
          anyNotNullColumnHasValue = true;
          break;
        }
      }
    }
    return anyNotNullColumnHasValue;
  }

  private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException {
    ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
    return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
  }

  //
  // UNIQUE RESULT KEY
  //

  private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
    //创建 CacheKey 对象
    final CacheKey cacheKey = new CacheKey();
    //ResultMap 作为 CacheKey 的一部分
    cacheKey.update(resultMap.getId());
    //／查找 ResultMapping 对象集合
    List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
    //没有找到任何 ResultMapping
    if (resultMappings.size() == 0) {
      if (Map.class.isAssignableFrom(resultMap.getType())) {
        //／由结果集中的所有列名以及当前记录行的所有列值一起构成 CacheKey 对象
        createRowKeyForMap(rsw, cacheKey);
      } else {
        //由结果集中未映射的列名以及它们在当前记录中中的对应列值一起构成 CacheKey 对象
        createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
      }
    } else {
      //由resultMappings 集合中的列名以及它们在当前记录行中相应的列值一起构成 CacheKey
      createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
    }
    //如采通过上面的查找没有找到任何列参与 构成 CacheKey 对象，则返 NullCacheKey 对象（略）
    return cacheKey;
  }

  private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {
    if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {
      CacheKey combinedKey;
      try {
        //注意，使用的是 rowKey 的克隆对象
        combinedKey = rowKey.clone();
      } catch (CloneNotSupportedException e) {
        throw new ExecutorException("Error cloning cache key.  Cause: " + e, e);
      }
      //与外层对象的 CacheKey 合并，形成嵌套对象最终的 Cache Key
      combinedKey.update(parentRowKey);
      return combinedKey;
    }
    return CacheKey.NULL_CACHE_KEY;
  }

  private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
    //ResultMap.idResultMappings 集合中记录<id.Arg>和<id>节点对 ResultMapping 对象
    List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
    if (resultMappings.size() == 0) {
      //ResultMap.propertyResultMappings 集合记录了除 <id ＊＞ 节点之外的 ResultMapping 对象
      resultMappings = resultMap.getPropertyResultMappings();
    }
    return resultMappings;
  }

  private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
    //遥历所有 resultMappings 集合
    for (ResultMapping resultMapping : resultMappings) {
      //如采存在嵌套映射， 革归调用 createRowKeyForMappedProperties()方法进行处理
      if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {
        // Issue #392
        final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
        createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(),
            prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
        //忽略嵌套查询
      } else if (resultMapping.getNestedQueryId() == null) {
        //获取该列的名称
        final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
        //获取列相 TypeHandler 对象
        final TypeHandler<?> th = resultMapping.getTypeHandler();
        //获取映射的列名
        List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
        // Issue #114
        if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
          // 获取列值
          final Object value = th.getResult(rsw.getResultSet(), column);
          if (value != null) {
            //将列名和列值添加到CacheKey对象中
            cacheKey.update(column);
            cacheKey.update(value);
          }
        }
      }
    }
  }

  private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {
    final MetaClass metaType = MetaClass.forClass(resultMap.getType());
    List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
    for (String column : unmappedColumnNames) {
      String property = column;
      if (columnPrefix != null && !columnPrefix.isEmpty()) {
        // When columnPrefix is specified, ignore columns without the prefix.
        if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
          property = column.substring(columnPrefix.length());
        } else {
          continue;
        }
      }
      if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
        String value = rsw.getResultSet().getString(column);
        if (value != null) {
          cacheKey.update(column);
          cacheKey.update(value);
        }
      }
    }
  }

  private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
    List<String> columnNames = rsw.getColumnNames();
    for (String columnName : columnNames) {
      final String value = rsw.getResultSet().getString(columnName);
      if (value != null) {
        cacheKey.update(columnName);
        cacheKey.update(value);
      }
    }
  }

}
